package ihm.controllers;

import characters.Characters;
import systems.database.query.Query;
import systems.database.query.condition.Condition;
import systems.exceptions.equipments.CanNotEquipThisItem;
import systems.rpgBuilder.Item;
import equipments.Items;
import equipments.enumeration.EquipmentSlots;
import ihm.models.ATKmodel;
import ihm.views.ATKview;
import ihm.views.main.MainFrame;

/**
 * This class provides a controller for the ATK program. 
 * According to the M-V-C design pattern a Controller receives input and 
 * initiates a response by making calls on model objects.
 * /!\The controller does not handle the character's statistics directly.
 * In order to change handle the character's statistics please take a look
 * at the ATKmodel and Character classes.
 * @author Baptiste Legrand & Benjamin Orman
 * @version 1.0
 */
public class ATKcontroller {
  /**
   * The ATKview which will be used as the main view
   */
  public ATKview mainView = null;
  /**
   * The ATKmodel which will contain all the data require for this program.
   */
  private ATKmodel model = null;

  /**
   * Create a controller which will be use by the user to handle the ATKmodel.
   * @param model - The model which will be manipulate by the the controller.
   */
  public ATKcontroller(ATKmodel model)
  {
    //Save the model.
    this.model = model;
    //Create the MainFrame.
    this.mainView = new MainFrame(this);
    //Register the MainFrame to the model as a Listener
    this.addListenersToModel();
  }

  /**
   * This method register all the ATKview to the model as a Listener.
   */
  private void addListenersToModel()
  {
    System.out.println("[Controller] - Enregistrement d'un listener au model.");
    this.model.addATKlistener(mainView);
  }

  /**
   * This method displays all the views create in the controller.
   */
  public void displayViews()
  {
    this.mainView.display();
  }

  /**
   * This method closes all the views displayed.
   */
  public void closeViews()
  {
    this.mainView.close();
  }

  /**
   * Getter returning the ATKmodel linked to the controller.
   * @return ATKmodel - the ATKmodel instance.
   */
  public ATKmodel getModel()
  {
    return this.model;
  }

  /**
   * Notify the model that the language used for the program changed.
   * The name of the new language is given in parameter.
   * @param newLanguage - the name of the new language.
   */
  public void notifyLanguageChanged(String newLanguage)
  {
    System.out.println("[Controller] - Notification d'un nouveau language.");
    this.model.setLanguage(newLanguage);
  }

  /**
   * Notify the model that the character's equipments changed and more 
   * precisely that the EquipmentsSlot <i>slot</i> is equipped with the Items 
   * <i>equipmentPart</i>.
   * However, if this action failed, a CanNotEquipThisItem exception
   * will be throw.
   * @param slot - The EquipmentsSlot where to put the new item. 
   * @param equipmentPart - The Items which will equip the character.
   * @see ATKmodel and Character documentation for more informations.
   * @throws CanNotEquipThisItem - This exception will be throws if the user
   * try to equip an Items and it fail.
   * @see CanNotEquipThisItem and Character class for more details about the
   * causes of this exception.
   */
  public void notifyEquipmentChanged(EquipmentSlots slot, Items equipmentPart)
  throws CanNotEquipThisItem
  {
    System.out.println("[Controller] - Notification d'un nouvel equipement.");
    this.model.setEquipments(slot, equipmentPart);
  }

  
  /**
   * Notify the model that the query changed and more precisely that the
   * condition of the query is replace by the <i>newCondition</i>.
   * @param newCondition - The new Condition of the query contains in the model.
   */
  public void notifyQueryChanged(Condition newCondition)
  {
    System.out.println("[Controller] - Notification d'une nouvelle condition sur la requete.");
    this.model.setQueryCondition(newCondition);
  }
  /**
   * Notify the model that the query is replaced with the <i>newQuery</i>.
   * @param newQuery - The new Query for the model.
   */
  public void notifyQueryChanged(Query newQuery)
  {
    System.out.println("[Controller] - Notification d'une nouvelle requete.");
    this.model.setQuery(newQuery);
  }

  /**
   * Notify the model that the item selected in the item tree changed.
   * @param itemSelected - The new Item selected in the item tree.
   */
  public void notifyItemTypeChanged(Item itemSelected)
  {
    System.out.println("[Controller] - Notification d'un nouvel item.");
    this.model.setTreeSelectedItem(itemSelected);
  }
  
  /**
   * Notify the model that the character used in the program changed.
   * Note: When you update the character you automatically update his equipment
   * @param newCharacter - The new Characters which will be use in the program.
   */
  public void notifyCharacterChanged(Characters newCharacter)
  {
    System.out.println("[Controller] - Notification d'un nouveau personnage");
    System.out.println("[Controller] - Mastery list size nouveau perso: "+newCharacter.getMasteryList().size());
    this.model.setCharacter(newCharacter);
  }
}
